import { oav } from '@feng3d/objectview';
import { mathUtil } from '@feng3d/polyfill';
import { Serializable, SerializeProperty } from '@feng3d/serialization';
import type { Color4 } from './Color4';
import { Vector3 } from './geom/Vector3';

declare module '@feng3d/serialization' { interface SerializableMap { Color3: Color3 } }

/**
 * 颜色
 */
@Serializable('Color3')
export class Color3
{
    declare __class__: 'Color3';

    static get WHITE()
    {
        return this._WHITE = this._WHITE || Object.freeze(new Color3(1, 1, 1));
    }
    private static _WHITE: Readonly<Color3>;

    static get BLACK()
    {
        return this._BLACK = this._BLACK || Object.freeze(new Color3(0, 0, 0));
    }
    private static _BLACK: Readonly<Color3>;

    static fromUnit(color: number)
    {
        return new Color3().fromUnit(color);
    }

    static fromColor4(color4: Color4)
    {
        return new Color3(color4.r, color4.g, color4.b);
    }

    /**
     * 红[0,1]
     */
    @oav()
    @SerializeProperty()
    r = 1;

    /**
     * 绿[0,1]
     */
    @oav()
    @SerializeProperty()
    g = 1;

    /**
     * 蓝[0,1]
     */
    @oav()
    @SerializeProperty()
    b = 1;

    /**
     * 构建颜色
     * @param r 红[0,1]
     * @param g 绿[0,1]
     * @param b 蓝[0,1]
     */
    constructor(r = 1, g = 1, b = 1)
    {
        this.r = r;
        this.g = g;
        this.b = b;
    }

    setTo(r: number, g: number, b: number)
    {
        this.r = r;
        this.g = g;
        this.b = b;

        return this;
    }

    /**
     * 通过
     * @param color
     */
    fromUnit(color: number)
    {
        this.r = ((color >> 16) & 0xff) / 0xff;
        this.g = ((color >> 8) & 0xff) / 0xff;
        this.b = (color & 0xff) / 0xff;

        return this;
    }

    toInt()
    {
        const value = ((this.r * 0xff) << 16) + ((this.g * 0xff) << 8) + (this.b * 0xff);

        return value;
    }

    /**
     * 输出16进制字符串
     */
    toHexString(): string
    {
        const intR = (this.r * 0xff) | 0;
        const intG = (this.g * 0xff) | 0;
        const intB = (this.b * 0xff) | 0;

        return `#${Color3.ToHex(intR)}${Color3.ToHex(intG)}${Color3.ToHex(intB)}`;
    }

    /**
     * 混合颜色
     * @param color 混入的颜色
     * @param rate 混入比例
     */
    mix(color: Color3, rate: number)
    {
        this.r = this.r * (1 - rate) + color.r * rate;
        this.g = this.g * (1 - rate) + color.g * rate;
        this.b = this.b * (1 - rate) + color.b * rate;

        return this;
    }

    /**
     * 混合颜色
     * @param color 混入的颜色
     * @param rate 混入比例
     */
    mixTo(color: Color3, rate: number, vout = new Color3())
    {
        return vout.copy(this).mix(color, rate);
    }

    /**
     * 按标量（大小）缩放当前的 Color3 对象。
     */
    scale(s: number)
    {
        this.r *= s;
        this.g *= s;
        this.b *= s;

        return this;
    }

    /**
     * 按标量（大小）缩放当前的 Color3 对象。
     */
    scaleTo(s: number, vout = new Color3())
    {
        return vout.copy(this).scale(s);
    }

    /**
     * 通过将当前 Color3 对象的 r、g 和 b 元素与指定的 Color3 对象的 r、g 和 b 元素进行比较，确定这两个对象是否相等。
     */
    equals(object: Color3, precision = mathUtil.PRECISION)
    {
        if (!mathUtil.equals(this.r - object.r, 0, precision))
        { return false; }
        if (!mathUtil.equals(this.g - object.g, 0, precision))
        { return false; }
        if (!mathUtil.equals(this.b - object.b, 0, precision))
        { return false; }

        return true;
    }

    /**
     * 拷贝
     */
    copy(color: Color3)
    {
        this.r = color.r;
        this.g = color.g;
        this.b = color.b;

        return this;
    }

    clone()
    {
        return new Color3(this.r, this.g, this.b);
    }

    toVector3(vector3 = new Vector3())
    {
        vector3.x = this.r;
        vector3.y = this.g;
        vector3.z = this.b;

        return vector3;
    }

    /**
     * 输出字符串
     */
    toString(): string
    {
        return `{R: ${this.r} G:${this.g} B:${this.b}}`;
    }

    /**
     * 转换为数组
     * @param array 数组
     * @param offset 偏移
     */
    toArray(array: number[] = [], offset = 0)
    {
        array[offset] = this.r;
        array[offset + 1] = this.g;
        array[offset + 2] = this.b;

        return array;
    }

    /**
     * [0,15]数值转为16进制字符串
     * param i  [0,15]数值
     */
    static ToHex(i: number): string
    {
        const str = i.toString(16);

        if (i <= 0xf)
        {
            return (`0${str}`).toUpperCase();
        }

        return str.toUpperCase();
    }
}

export const ColorKeywords = {
    aliceblue: 0xF0F8FF, antiquewhite: 0xFAEBD7, aqua: 0x00FFFF, aquamarine: 0x7FFFD4, azure: 0xF0FFFF,
    beige: 0xF5F5DC, bisque: 0xFFE4C4, black: 0x000000, blanchedalmond: 0xFFEBCD, blue: 0x0000FF, blueviolet: 0x8A2BE2,
    brown: 0xA52A2A, burlywood: 0xDEB887, cadetblue: 0x5F9EA0, chartreuse: 0x7FFF00, chocolate: 0xD2691E, coral: 0xFF7F50,
    cornflowerblue: 0x6495ED, cornsilk: 0xFFF8DC, crimson: 0xDC143C, cyan: 0x00FFFF, darkblue: 0x00008B, darkcyan: 0x008B8B,
    darkgoldenrod: 0xB8860B, darkgray: 0xA9A9A9, darkgreen: 0x006400, darkgrey: 0xA9A9A9, darkkhaki: 0xBDB76B, darkmagenta: 0x8B008B,
    darkolivegreen: 0x556B2F, darkorange: 0xFF8C00, darkorchid: 0x9932CC, darkred: 0x8B0000, darksalmon: 0xE9967A, darkseagreen: 0x8FBC8F,
    darkslateblue: 0x483D8B, darkslategray: 0x2F4F4F, darkslategrey: 0x2F4F4F, darkturquoise: 0x00CED1, darkviolet: 0x9400D3,
    deeppink: 0xFF1493, deepskyblue: 0x00BFFF, dimgray: 0x696969, dimgrey: 0x696969, dodgerblue: 0x1E90FF, firebrick: 0xB22222,
    floralwhite: 0xFFFAF0, forestgreen: 0x228B22, fuchsia: 0xFF00FF, gainsboro: 0xDCDCDC, ghostwhite: 0xF8F8FF, gold: 0xFFD700,
    goldenrod: 0xDAA520, gray: 0x808080, green: 0x008000, greenyellow: 0xADFF2F, grey: 0x808080, honeydew: 0xF0FFF0, hotpink: 0xFF69B4,
    indianred: 0xCD5C5C, indigo: 0x4B0082, ivory: 0xFFFFF0, khaki: 0xF0E68C, lavender: 0xE6E6FA, lavenderblush: 0xFFF0F5, lawngreen: 0x7CFC00,
    lemonchiffon: 0xFFFACD, lightblue: 0xADD8E6, lightcoral: 0xF08080, lightcyan: 0xE0FFFF, lightgoldenrodyellow: 0xFAFAD2, lightgray: 0xD3D3D3,
    lightgreen: 0x90EE90, lightgrey: 0xD3D3D3, lightpink: 0xFFB6C1, lightsalmon: 0xFFA07A, lightseagreen: 0x20B2AA, lightskyblue: 0x87CEFA,
    lightslategray: 0x778899, lightslategrey: 0x778899, lightsteelblue: 0xB0C4DE, lightyellow: 0xFFFFE0, lime: 0x00FF00, limegreen: 0x32CD32,
    linen: 0xFAF0E6, magenta: 0xFF00FF, maroon: 0x800000, mediumaquamarine: 0x66CDAA, mediumblue: 0x0000CD, mediumorchid: 0xBA55D3,
    mediumpurple: 0x9370DB, mediumseagreen: 0x3CB371, mediumslateblue: 0x7B68EE, mediumspringgreen: 0x00FA9A, mediumturquoise: 0x48D1CC,
    mediumvioletred: 0xC71585, midnightblue: 0x191970, mintcream: 0xF5FFFA, mistyrose: 0xFFE4E1, moccasin: 0xFFE4B5, navajowhite: 0xFFDEAD,
    navy: 0x000080, oldlace: 0xFDF5E6, olive: 0x808000, olivedrab: 0x6B8E23, orange: 0xFFA500, orangered: 0xFF4500, orchid: 0xDA70D6,
    palegoldenrod: 0xEEE8AA, palegreen: 0x98FB98, paleturquoise: 0xAFEEEE, palevioletred: 0xDB7093, papayawhip: 0xFFEFD5, peachpuff: 0xFFDAB9,
    peru: 0xCD853F, pink: 0xFFC0CB, plum: 0xDDA0DD, powderblue: 0xB0E0E6, purple: 0x800080, rebeccapurple: 0x663399, red: 0xFF0000, rosybrown: 0xBC8F8F,
    royalblue: 0x4169E1, saddlebrown: 0x8B4513, salmon: 0xFA8072, sandybrown: 0xF4A460, seagreen: 0x2E8B57, seashell: 0xFFF5EE,
    sienna: 0xA0522D, silver: 0xC0C0C0, skyblue: 0x87CEEB, slateblue: 0x6A5ACD, slategray: 0x708090, slategrey: 0x708090, snow: 0xFFFAFA,
    springgreen: 0x00FF7F, steelblue: 0x4682B4, tan: 0xD2B48C, teal: 0x008080, thistle: 0xD8BFD8, tomato: 0xFF6347, turquoise: 0x40E0D0,
    violet: 0xEE82EE, wheat: 0xF5DEB3, white: 0xFFFFFF, whitesmoke: 0xF5F5F5, yellow: 0xFFFF00, yellowgreen: 0x9ACD32
};

